#include "ireactor.h"
#include "iaccepterhandler.h"

#include "netaddress.h"
#include "tcpaccepter.h"
#include "internalenv.h"

#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>

namespace net {

TCPAccepter::TCPAccepter() {
	reactor = GetReactor();

	fd = socket(AF_INET, SOCK_STREAM, 0);
	SetBlock(true);
    assert(ReuseAddr() != -1);
}

TCPAccepter::~TCPAccepter() {
	if(fd != -1) {
		close(fd);
		fd = -1;
	}
}

void TCPAccepter::Close() {
	delete this;
}

void TCPAccepter::SetHandler(IAccepterHandler* handler) {
	this->handler = handler;
}

bool TCPAccepter::Listen(NetAddress& address) {
	assert(fd != -1);		

	sockaddr_in addr = {0};
	addr.sin_family = AF_INET;
	addr.sin_port = address.GetNetPort();
	addr.sin_addr.s_addr = address.GetIp();

	//1.监听
	int ret = bind(fd, (sockaddr*)&addr, sizeof(sockaddr));
	assert(ret != -1);

	ret = listen(fd, MAX_LISTEN_SIZE);
	assert(ret != -1);

	int optval = 1;
	ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

	//2.增加到Reacotr中
	reactor->AddEvent(this, Read);
	assert(ret != -1);
	return ret != -1;
}

uint32_t TCPAccepter::GetFd() {
	return fd;
}

void TCPAccepter::OnEvent(uint32_t event_type) {
	while(1) {
		int client = accept(fd, NULL, 0);
		if(client == -1) {
			return ;
		}
		ISocket* socket = GetSocket(client);
		if(handler) {
			handler->OnAccept(socket);
		}
	}
}

bool TCPAccepter::SetBlock(bool is_block) {
	int flag = fcntl(fd, F_GETFL);
	if(flag == -1) {
		return false;
	}

	if(is_block) {
		flag = fcntl(fd, F_SETFL, flag | O_NONBLOCK);
	}
	else {
		flag = fcntl(fd, F_SETFL, flag & (~O_NONBLOCK));
	}

	if(flag == -1) {
		return false;
	}
	return true;
}

bool TCPAccepter::ReuseAddr() {
    int opt = 1;
    socklen_t len = sizeof(opt);
    return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
}

}
